/* Copyright (C) 2010 Luca Piccinelli
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdexcept>
#include <algorithm>

#include "configuration/configuration.h"
#include "exceptions/factory_exceptions.h"
#include "common/utility_data_structures.h"

using namespace std;
using namespace boost;

namespace NAMESPACE{
// ****** ConfigurationTemplate implementation *********************************
//  _____________________________________________________
// |   Standard constructors                             |
// |_____________________________________________________|

ConfigurationTemplate::~ConfigurationTemplate(){}
ConfigurationTemplate::ConfigurationTemplate() : params_set() {}
ConfigurationTemplate::ConfigurationTemplate(const ConfigurationTemplate& ct) : params_set(ct.params_set) {}
ConfigurationTemplate& ConfigurationTemplate::operator=(const ConfigurationTemplate& ct){
    if(this == &ct) return *this;
    params_set = ct.params_set;
    return *this;
}

// .............................................................................

ConfigurationTemplate& ConfigurationTemplate::add(const IOKey& key){
    params_set.push_back(key);
    return *this;
}

const IOKey& ConfigurationTemplate::param_at(int idx) const throw(std::out_of_range){
    return params_set.at(idx);
}

bool ConfigurationTemplate::contains(const IOKey& key) const{
    set_t::const_iterator it = std::find(params_set.begin(), params_set.end(), key);
    return it != params_set.end();
}

size_t ConfigurationTemplate::parameters_num() const {return params_set.size();}


// ****** Configuration implementation *****************************************
//  _____________________________________________________
// |   Standard constructors                             |
// |_____________________________________________________|

Configuration::~Configuration(){
    params_map_t::iterator it = params.begin();
    for(; it != params.end(); it++){
       if(it->second) delete it->second;
    }
}
Configuration::Configuration() : ct(), params(){}

Configuration::Configuration(const Configuration& c) : ct(c.ct), params() {
    params_map_t::const_iterator it;
    for(it = c.params.begin(); it != c.params.end(); it++){
        params[it->first] = new boost::any(*(it->second));
    }
}
Configuration& Configuration::operator=(const Configuration& c){
    if(this == &c) return *this;
    
    params_map_t::iterator it = params.begin();
    for(; it != params.end(); it++){
        if(it->second) delete it->second;
        it->second = 0;
    }
    params.clear();
    
    params_map_t::const_iterator c_it;
    for(c_it = c.params.begin(); c_it != c.params.end(); c_it++){
        params[c_it->first] = new boost::any(*(c_it->second));
    }
    
    ct = c.ct;
    return *this;
}

Configuration::Configuration(const ConfigurationTemplate& _ct) : ct(_ct), params(){}
// ......................................................

Configuration& Configuration::set_template(const ConfigurationTemplate& _ct){
    params_map_t::iterator it = params.begin();
    for(; it != params.end(); it++){
        delete it->second;
        it->second = 0;
    }
    ct = _ct;

    return *this;
}

const ConfigurationTemplate& Configuration::get_template() const{
    return ct;
}

const Configuration::params_map_t& Configuration::get_all_params() const { return params; }
// -----------------------------------------------------------------------------
}
